package kwic.architecture;

import java.io.*;
import java.util.*;

/**
 * 事件系统体系结构实现KWIC。
 */
public class EventSystem {
    public static void main(String[] args) {
        KWICSubject kwicSubject = new KWICSubject();

        InputObserver input = new InputObserver("src/main/resources/input.txt");
        kwicSubject.addObserver(input);

        ShiftObserver shift = new ShiftObserver(input);
        kwicSubject.addObserver(shift);

        AlphabetizerObserver alphabetizer = new AlphabetizerObserver(shift);
        kwicSubject.addObserver(alphabetizer);

        OutputObserver output = new OutputObserver(alphabetizer, "src/main/resources/output1.txt");
        kwicSubject.addObserver(output);

        kwicSubject.notifyObservers();
    }
}

interface Observer {
    void update();
}

class KWICSubject {
    private List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

class InputObserver implements Observer {
    private String fileName;
    private ArrayList<String> lines = new ArrayList<>();

    public InputObserver(String fileName) {
        this.fileName = fileName;
    }

    public ArrayList<String> getLines() {
        return lines;
    }

    @Override
    public void update() {
        try (BufferedReader inputFile = new BufferedReader(new FileReader(fileName))) {
            String line;
            while ((line = inputFile.readLine()) != null) {
                lines.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class ShiftObserver implements Observer {
    private InputObserver input;
    private ArrayList<String> shifts = new ArrayList<>();

    public ShiftObserver(InputObserver input) {
        this.input = input;
    }

    public ArrayList<String> getShifts() {
        return shifts;
    }

    @Override
    public void update() {
        for (String line : input.getLines()) {
            StringTokenizer token = new StringTokenizer(line);
            ArrayList<String> tokens = new ArrayList<>();
            while (token.hasMoreTokens()) {
                tokens.add(token.nextToken());
            }
            for (int i = 0; i < tokens.size(); i++) {
                String shiftedLine = String.join(" ", tokens);
                shifts.add(shiftedLine);
                Collections.rotate(tokens, -1);
            }
        }
    }
}

class AlphabetizerObserver implements Observer {
    ShiftObserver shift;

    public AlphabetizerObserver(ShiftObserver shift) {
        this.shift = shift;
    }

    @Override
    public void update() {
        shift.getShifts().sort(String::compareToIgnoreCase);
    }
}

class OutputObserver implements Observer {
    private AlphabetizerObserver alphabetizer;
    private String fileName;

    public OutputObserver(AlphabetizerObserver alphabetizer, String fileName) {
        this.alphabetizer = alphabetizer;
        this.fileName = fileName;
    }

    @Override
    public void update() {
        try (BufferedWriter outputFile = new BufferedWriter(new FileWriter(fileName))) {
            for (String line : alphabetizer.shift.getShifts()) {
                outputFile.write(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
